package com.gagakuai.transport.bootstrap;

import com.gagakuai.transport.channel.*;
import com.gagakuai.utils.internal.ObjectUtil;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.LinkedHashMap;
import java.util.Map;

/*
 * @description: 抽象启动器
 * @author: houhong
 * @create: 2024-03-18 23:26
 */
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> {

    private volatile EventLoopGroup group;

    private volatile ChannelFactory<? extends C> channelFactory;


    private volatile ChannelHandler handler;

    private volatile SocketAddress localAddress;

    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<>();


    public final EventLoopGroup group() {
        return group;
    }

    public B group(EventLoopGroup group) {

        this.group = group;


        return self();
    }

    public B self() {

        return (B) this;
    }


    /*==============配置channel工厂，在bind的时候使用 来进行生成channel=============================*/
    public B channel(Class<? extends C> channelClass) {


        Class<? extends C> channelClass1 = ObjectUtil.checkNotNull(channelClass, "channelClass");

        return channelFactory(new ReflectiveChannelFactory<>(
                channelClass1
        ));
    }

    final ChannelFactory<? extends C> channelFactory() {
        return channelFactory;
    }

    public B channelFactory(com.gagakuai.transport.channel.ChannelFactory<? extends C> channelFactory) {

        return channelFactory((ChannelFactory<C>) channelFactory);
    }


    public B channelFactory(ChannelFactory<? extends C> channelFactory) {

        this.channelFactory = channelFactory;
        return self();
    }


    /*==============参数==================*/


    public <T> B opetions(ChannelOption<T> option, T value) {


        synchronized (options) {

            if (value == null) {
                options.remove(option);
            } else {
                options.put(option, value);
            }

        }

        return self();
    }


    public B validate() {
        if (group == null) {
            throw new IllegalStateException("group not set");
        }
        if (channelFactory == null) {
            throw new IllegalStateException("channel or channelFactory not set");
        }
        return self();
    }



    /*====================绑定端口=====================================*/


    public void bind(int port) {

        bind(new InetSocketAddress(port));
    }


    public void bind(SocketAddress socketAddress) {

        validate();

        doBind(ObjectUtil.checkNotNull(socketAddress, "socketAddress"));
    }


    public ChannelFuture doBind(final SocketAddress socketAddress) {

        ChannelFuture regFuture = initAndRegister();

        //异步回调完成绑定调channel -- 可以理解为线程回阻塞在这里 java.util.concurrent
        final Channel channel = regFuture.channel();


        if (regFuture.isDone()) {

            ChannelPromise channelPromise = channel.newChannelPromise();

            doBind0(regFuture, channel, socketAddress, channelPromise);
            return channelPromise;
        }

        return regFuture;

    }


    public void doBind0(final ChannelFuture regFuture, final Channel channel,
                        final SocketAddress localAddress, final ChannelPromise promise) {


        channel.eventLoop().execute(() -> {

            if (regFuture.isSuccess()) {

                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }

        });


    }


    /*
     * @return {@link ChannelFuture }
     * @description //todo 初始化一个channel：表示建立一个conneciton
     * 并且channel 注册到一个EventLoopGoup中
     * @author houhong
     */
    public ChannelFuture initAndRegister() {


        Channel channel = null;


        try {
            channel = channelFactory.newChannel();

            init(channel);
        } catch (Exception e) {


        }


        return config().group().register(channel);


    }


    abstract void init(Channel channel) throws Exception;



    /*================================配置===========================================*/

    public abstract AbstractBootstrapConfig<B, C> config();








    /*================================基础信息===========================================*/

    /*=*/
    final SocketAddress localAddress() {
        return localAddress;
    }


    public ChannelHandler handler() {

        return handler;
    }
}
